package com.deam.imsdk.imsdk;

import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.widget.Toast;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.deam.imsdk.R;
import com.deam.imsdk.bean.Conversation;
import com.deam.imsdk.bean.SMessage;
import com.deam.imsdk.bean.UserInfo;
import com.deam.imsdk.dao.ConversationDao;
import com.deam.imsdk.dao.DbManager;
import com.deam.imsdk.dao.UserDao;
import com.deam.imsdk.elem.BaseElem;
import com.deam.imsdk.elem.IMTextElem;
import com.deam.imsdk.greendao.ConversationDaoDao;
import com.deam.imsdk.greendao.DaoSession;
import com.deam.imsdk.greendao.UserDaoDao;
import com.deam.imsdk.net.TCPClient;
import com.deam.imsdk.utils.Constants;
import com.deam.imsdk.utils.UserUtil;

import org.greenrobot.greendao.query.QueryBuilder;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 即时通讯管理者
 * Created by Administrator on 2018/4/18.
 */

public class IMManager {
    private final Set<RequestResultListener> mRequestResultListeners = new HashSet<>();
    private final Set<ConversationListener> mConversationListener = new HashSet<>();
    private final Set<SMessage> mMessageListener = new HashSet<>();
    //好友上下线状态
    private final Set<StartAlterListener> mStartAlterListener = new HashSet<>();
    //网络状态改变回调
    private final Set<ConnectStateListener> mConnectStateListener = new HashSet<>();
    private static IMManager mIMManager;
    private boolean isLoaging = false;
    private final int pushId = 1;
    private int mConnectState = TCPClient.CONNECT_NO;

    public static IMManager getInstance() {
        if (mIMManager == null) {
            mIMManager = new IMManager();
        }
        return mIMManager;
    }

    /**
     * 第一次使用需要初始化
     *
     * @param context
     */
    public void init(Context context) {
        UserUtil.registerUserUtil(context);
        //启动接收广播
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Constants.IMS_BRPULL_STRING);
        context.registerReceiver(new IMPullReceiver(), intentFilter);
        // 启动通讯服务
        MiPushClient.registerPush(context);
    }

    public void login(@NonNull Context appContext, @NonNull String username) {
        JSONObject json = new JSONObject();
        json.put(Constants.REQUEST, Constants.ACTION_LOGING);
        json.put(Constants.USER_ACTION, Constants.ACTION_LOGING);
        json.put("username", username);
        MiPushClient.sendMessage(json.toJSONString());
    }

    /**
     * 更新好友列表
     */
    public void updateConversation() {
        updateConversationElem(getConversation());
        JSONObject json = new JSONObject();
        json.put(Constants.REQUEST, Constants.ACTION_CONSTANTS);
        json.put(Constants.USER_ACTION, Constants.ACTION_CONSTANTS);
        MiPushClient.sendMessage(json.toJSONString());
    }

    /**
     * 注册 状态更新回调
     *
     * @param listener
     */
    public synchronized void registermStartAlter(StartAlterListener listener) {
        mStartAlterListener.add(listener);
    }

    /**
     * 销毁
     *
     * @param listener
     */
    public synchronized void unRegistermStartAlter(Object listener) {
        mStartAlterListener.remove(listener);
    }

    /**
     * 注册 状态更新回调
     *
     * @param listener
     */
    public synchronized void registermConnectState(ConnectStateListener listener) {
        mConnectStateListener.add(listener);
        listener.onStateAlter(mConnectState);
    }

    /**
     * 销毁
     *
     * @param listener
     */
    public synchronized void unRegistermConnectState(Object listener) {
        mConnectStateListener.remove(listener);
    }

    /**
     * 注册 好友更新回调
     *
     * @param listener
     */
    public synchronized void registerConversation(ConversationListener listener) {
        mConversationListener.add(listener);
    }

    /**
     * 注册 请求回调
     *
     * @param listener
     */
    public synchronized void registerRequestReturn(RequestResultListener listener) {
        mRequestResultListeners.add(listener);
    }

    /**
     * 销毁
     *
     * @param listener
     */
    public synchronized void unRegisterRequestReturn(Object listener) {
        mRequestResultListeners.remove(listener);
    }

    /**
     * 销毁
     *
     * @param listener
     */
    public synchronized void unRegisterConversation(Object listener) {
        mConversationListener.remove(listener);
    }


    /**
     * 添加消息监听
     *
     * @param user_id  监听的用户id
     * @param listener
     */
    public synchronized void registerMessageListener(String user_id, MessageListener listener) {
        mMessageListener.add(new SMessage(listener, user_id));
        listener.messageList(getByUserIdElem(user_id, false));
    }

    /**
     * 删除消息监听
     *
     * @param listener
     */
    public synchronized void unRegisterMessageListener(Object listener) {
        Set<SMessage> a = new HashSet<>();
        Iterator<SMessage> it = mMessageListener.iterator();
        while (it.hasNext()) {
            SMessage l = it.next();
            if (l.getMessageListener() == listener) {
                a.add(l);
            }
        }
        mMessageListener.removeAll(a);
    }

    public String getUserId() {
        return UserUtil.getUser().getUserId();
    }

    /**
     * 接收IM消息的 接收器
     */
    class IMPullReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String im_msg = intent.getStringExtra(Constants.IMS_MESSAGE);
            Toast.makeText(context, im_msg, Toast.LENGTH_LONG);
            if (im_msg != null) {
                JSONObject json = JSONObject.parseObject(im_msg);
                int requestCode = json.getIntValue(Constants.REQUEST);
                int code = json.getIntValue(Constants.CODE);
                switch (code) {
                    case Constants.CODE_OK:
                        distribute(json);
                        break;
                    case Constants.CODE_PAST_INFO:
                    case Constants.CODE_ERROR:
                        onCllBackErrorMessage(requestCode, json.getString(Constants.MSG));
                        errorDistribute(requestCode, json);
                        break;
                    case 0:
                        distributeRestAction(json);
                        break;
                }
            }
        }
    }

    /**
     * 分发其他动作
     */
    private void distributeRestAction(JSONObject json) {
        int userAction = json.getIntValue(Constants.USER_ACTION);
        switch (userAction) {
            case Constants.ACTION_UPDATE_START://有用户改变状态
                updateStart(json);
                break;
            case Constants.ACTION_HEART_BEAT1:
                //心跳请求回
                int hb = json.getIntValue(Constants.HB);
                long timg = json.getLongValue(Constants.EL_TIME);
                if (hb == Constants.HB_REQUEST) {
                    //客户的心跳请求
                    MiPushClient.sendMessage(getHeartBeatResult(timg).toJSONString());
                } else if (hb == Constants.HB_RESULT) {
                    //服务器的心跳请求回执结果（到此表示心跳成功）

                }
                break;
            case Constants.ACTION_CONNECT_UPDATE:
                //连接状态改变
                connectSteteDistribute(json.getIntValue("state"));
                break;
        }
    }

    /**
     * 退出操作
     */
    public void exit() {
        JSONObject json = new JSONObject();
        json.put(Constants.USER_ACTION, Constants.ACTION_EXIT);
        MiPushClient.sendMessage(json.toJSONString());
        UserUtil.clearCache();
    }

    /**
     * 返回错误信息
     *
     * @param code 错误码
     * @param msg
     */
    private void onCllBackErrorMessage(int code, String msg) {
        synchronized (IMManager.this) {
            Iterator<RequestResultListener> it = mRequestResultListeners.iterator();
            while (it.hasNext()) {
                RequestResultListener listener = it.next();
                listener.onError(code, msg);
            }
        }
    }

    /**
     * 返回 发送消息请求回调
     *
     * @param code
     * @param identifying
     * @param msg
     */
    private void onCllBackSendMessageError(int code, String identifying, String msg) {
        synchronized (IMManager.this) {
            Iterator<SMessage> it = mMessageListener.iterator();
            while (it.hasNext()) {
                SMessage listener = it.next();
                if (listener.getMessageListener() != null) {
                    listener.getMessageListener().sendMessageResult(code, identifying, msg);
                }
            }
        }
    }

    /**
     * 返回成功消息
     *
     * @param reqId 请求码
     * @param json  成功数据体
     */
    private void onCllBackSuccessMessage(int reqId, JSONObject json) {
        synchronized (IMManager.this) {
            Iterator<RequestResultListener> it = mRequestResultListeners.iterator();
            while (it.hasNext()) {
                RequestResultListener listener = it.next();
                listener.onSuccess(reqId, json);
            }
        }
    }

    //失败请求处理消息分发处理
    private void errorDistribute(int requestCode, JSONObject json) {
        String error_msg = json.getString("msg");
        switch (requestCode) {
            case Constants.ACTION_TYPE_TEXT:
                IMTextElem textElem = new IMTextElem(json);
                //发送消息
                onCllBackSendMessageError(Constants.CODE_ERROR, textElem.getIdentifying(), error_msg);
                break;
        }
    }

    //消息分发处理
    private void distribute(JSONObject json) {
        int requestCode = json.getIntValue(Constants.REQUEST);
        switch (requestCode) {
            case Constants.ACTION_LOGING:
                UserInfo info = new UserInfo();
                info.setUserId(json.getString(UserInfo.USER_ID));
                info.setToken(json.getString(UserInfo.TOKEN));
                info.setNetname(json.getString(UserInfo.NETNAME));
                if (info.getUserId() == null) {
                    onCllBackErrorMessage(-1, "获取用户信息失败");
                    return;
                }
                isLoaging = true;
                UserUtil.commitUser(info);
                break;
            case Constants.ACTION_UPDATE_START:
                updateStart(json);
            case Constants.ACTION_TYPE_TEXT:
                IMTextElem textElem = new IMTextElem(json);
                textElem.setSendState(BaseElem.SEND_STATE_OK);
                updateSendElem(textElem);
                updateDBMessage(textElem);
                onCllBackSendMessageError(Constants.CODE_OK, textElem.getIdentifying(), "OK");
                break;
            case Constants.ACTION_CONSTANTS:
                List<Conversation> list = new ArrayList<>();
                JSONArray cList = json.getJSONArray("list");
                for (int i = 0; i < cList.size(); i++) {
                    JSONObject cC = cList.getJSONObject(i);
                    JSONObject elem = JSONObject.parseObject(cC.getString("elem"));
                    Conversation c = new Conversation();
                    c.setUserId(cC.getString(UserInfo.USER_ID));
                    c.setNetname(cC.getString(UserInfo.NETNAME));
                    c.setStart(cC.getIntValue(UserInfo.START));
                    c.setElem(new IMTextElem(elem));
                    list.add(c);
                }
                updateDBConversation(list);
                updateConversationElem(getConversation());
                break;
        }
        onCllBackSuccessMessage(requestCode, json);
    }

    /**
     * 更新消息数据库
     *
     * @param textElem
     */
    private void updateDBMessage(IMTextElem textElem) {
        ConversationDao message = getDaoSession().getConversationDaoDao().queryBuilder().where(ConversationDaoDao.Properties.Identifying.eq(textElem.getIdentifying())).unique();
        if (message == null) {
            message = new ConversationDao();
            message.setAcceptorId(textElem.getAcceptorId());
            message.setContext(textElem.getContext());
            message.setSenderId(textElem.getSenderId());
            message.setTime(textElem.getTime());
            message.setType(textElem.getType().name());
            message.setIdentifying(textElem.getIdentifying());
            getDaoSession().getConversationDaoDao().insert(message);
        }
    }

    /**
     * 更新数据库消息列表
     */
    private void updateDBConversation(List<Conversation> list) {
        List<UserDao> insetUser = new ArrayList<>();
        List<UserDao> daoList = getDaoSession().getUserDaoDao().queryBuilder().build().list();
        for (int i = 0; i < daoList.size(); i++) {
            daoList.get(i).setStart(UserInfo.START_US);
        }
        //更新数据
        for (int i = 0; i < list.size(); i++) {
            Conversation c = list.get(i);
            String user_id = c.getUserId();
            if (user_id == null) continue;
            boolean isupd = false;
            for (int j = 0; j < daoList.size(); j++) {
                UserDao ud = daoList.get(j);
                String duser_id = "" + ud.getId();
                if (user_id.equals(duser_id)) {
                    ud.setNetname(c.getNetname());
                    ud.setStart(c.getStart());
                    isupd = true;
                    break;
                }
            }
            if (!isupd) {
                insetUser.add(new UserDao(Long.valueOf(user_id), c.getNetname(), "", c.getStart()));
            }
        }
        //更新用户列表数据
        if (daoList.size() != 0) getDaoSession().getUserDaoDao().updateInTx(daoList);
        if (insetUser.size() != 0) getDaoSession().getUserDaoDao().insertInTx(insetUser);
    }

    /**
     * 给所有注册会话回调的 地方发送消息
     *
     * @param list
     */
    private void updateConversationElem(List<Conversation> list) {
        if (list != null) {
            synchronized (IMManager.this) {
                Iterator<ConversationListener> it = mConversationListener.iterator();
                while (it.hasNext()) {
                    ConversationListener listener = it.next();
                    listener.updateConversation(list);
                }
            }
        }
    }

    /**
     * 给有注册聊天消息回调的 地方发送消息
     *
     * @param elem
     */
    private void updateSendElem(BaseElem elem) {
        if (elem != null) {
            updateConversationMessage(elem);
            if (elem.getSenderId().equals(getUserId())) return;
            synchronized (IMManager.this) {
                Iterator<SMessage> it = mMessageListener.iterator();
                while (it.hasNext()) {
                    SMessage listener = it.next();
                    if (elem.getSenderId() == null || listener.getUserId() == null) continue;
                    if (listener.getUserId().equals(elem.getSenderId()) || listener.getUserId().equals(elem.getAcceptorId())) {
                        listener.getMessageListener().update(elem);
                    }
                }
            }
            if (getUserId() != null && !getUserId().equals(elem.getSenderId())) {
                Context context = MiPushClient.getContext();
                List<UserDao> userDaos = getUserDb(elem.getSenderId());
                UserDao user = userDaos.size() != 0 ? userDaos.get(0) : null;
                Notification notify = new Notification.Builder(context)
                        .setSmallIcon(R.mipmap.ic_launcher00) // 设置状态栏中的小图片，尺寸一般建议在24×24， 这里也可以设置大图标
                        .setTicker(user == null ? elem.getSenderId() : user.getNetname())// 设置显示的提示文字
                        .setContentTitle(user == null ? elem.getSenderId() : user.getNetname())// 设置显示的标题
                        .setContentText(elem.getContext())// 消息的详细内容
                        .setDefaults(Notification.DEFAULT_ALL)//向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置，使用defaults属性，可以组合
                        .setNumber(1) // 在TextView的右方显示的数字，可以在外部定义一个变量，点击累加setNumber(count),这时显示的和
                        .getNotification(); // 需要注意build()是在API level16及之后增加的，在API11中可以使用getNotificatin()来代替
                notify.flags |= Notification.FLAG_AUTO_CANCEL;
                NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                manager.notify(pushId, notify);
            }
        }
    }

    /**
     * 消息列表消息回调
     *
     * @param elem
     */
    private void updateConversationMessage(BaseElem elem) {
        synchronized (IMManager.this) {
            Iterator<ConversationListener> it = mConversationListener.iterator();
            while (it.hasNext()) {
                ConversationListener listener = it.next();
                listener.updateMessage(elem);
            }
        }
    }

    /**
     * 好友状态更新
     *
     * @param json
     */
    private void updateStart(JSONObject json) {
        String user_id = json.getString(UserInfo.USER_ID);
        int start = json.getIntValue(UserInfo.START);
        if (user_id == null) return;
        List<UserDao> userDaos = getDaoSession().getUserDaoDao().queryBuilder().where(UserDaoDao.Properties.Id.eq(user_id)).list();
        if (userDaos.size() != 0) {
            UserDao userDao = userDaos.get(0);
            userDao.setStart(start);
            getDaoSession().getUserDaoDao().update(userDao);
        }
        synchronized (IMManager.this) {
            Iterator<StartAlterListener> it = mStartAlterListener.iterator();
            while (it.hasNext()) {
                StartAlterListener listener = it.next();
                listener.updateStart(user_id, start);
            }
        }
    }

    /**
     * 网络状态 分发
     *
     * @param state
     */
    private void connectSteteDistribute(int state) {
        mConnectState = state;
        synchronized (IMManager.this) {
            Iterator<ConnectStateListener> it = mConnectStateListener.iterator();
            while (it.hasNext()) {
                ConnectStateListener listener = it.next();
                listener.onStateAlter(state);
            }
        }
    }

    private List<UserDao> getUserDb() {
        return getUserDb(null);
    }

    private List<UserDao> getUserDb(String user_id) {
        QueryBuilder queryBuilder = getDaoSession().getUserDaoDao().queryBuilder();
        if (user_id != null) queryBuilder.where(UserDaoDao.Properties.Id.eq(user_id));
        return queryBuilder.build().list();
    }

    private DaoSession getDaoSession() {
        return DbManager.getDaoSession(MiPushClient.getContext());
    }

    private List<Conversation> getConversation() {
        List<Conversation> us = new ArrayList<>();
        List<UserDao> daoList = getUserDb();
        for (int i = 0; i < daoList.size(); i++) {
            UserDao userDao = daoList.get(i);
            Conversation c = new Conversation();
            c.setUserId("" + userDao.getId());
            c.setNetname(userDao.getNetname());
            c.setStart(userDao.getStart());
            List<BaseElem> elems = getByUserIdElem(c.getUserId(), true);
            if (elems.size() != 0) {
                c.setElem(elems.get(0));
            }
            us.add(c);
        }
        return us;
    }

    /**
     * 根据用户id获取 消息列表
     *
     * @param user_id
     * @param desc    降序
     * @return
     */
    private List<BaseElem> getByUserIdElem(String user_id, boolean desc) {
        List<BaseElem> elems = new ArrayList<>();
        if (user_id == null) return elems;
        QueryBuilder queryBuilder = getDaoSession().getConversationDaoDao().queryBuilder().whereOr(
                ConversationDaoDao.Properties.AcceptorId.eq(user_id),
                ConversationDaoDao.Properties.SenderId.eq(user_id));
        if (desc) {
            queryBuilder.orderDesc(ConversationDaoDao.Properties.Time);
        } else {
            queryBuilder.orderAsc(ConversationDaoDao.Properties.Time);
        }
        List<ConversationDao> conversationDaos = queryBuilder.list();
        for (int i = 0; i < conversationDaos.size(); i++) {
            ConversationDao conversationDao = conversationDaos.get(i);
            String type = conversationDao.getType();
            if (type != null) {
                BaseElem elem = new IMTextElem();
                if (type.equals(BaseElem.ElemType.TEXT.name())) {
                    IMTextElem textElem = (IMTextElem) elem;
                    textElem.setTime(conversationDao.getTime());
                    textElem.setAcceptorId(conversationDao.getAcceptorId());
                    textElem.setSenderId(conversationDao.getSenderId());
                    textElem.setIdentifying(conversationDao.getIdentifying());
                    textElem.setContext(conversationDao.getContext());
                    textElem.setType(conversationDao.getType());
                    textElem.setSendState(BaseElem.SEND_STATE_OK);
                }
                elems.add(elem);
            }
        }
        return elems;
    }

    /**
     * 获取心跳请求 数据体
     *
     * @return
     */
    private JSONObject getHeartBeatRequest() {
        JSONObject json = new JSONObject();
        json.put(Constants.USER_ACTION, Constants.ACTION_HEART_BEAT1);
        json.put(Constants.HB, Constants.HB_REQUEST);
        json.put(Constants.EL_TIME, System.currentTimeMillis() / 1000);
        return json;
    }

    /**
     * 获取心跳回执数据
     *
     * @param request_time 心跳请求时间
     * @return
     */
    private JSONObject getHeartBeatResult(long request_time) {
        JSONObject json = new JSONObject();
        json.put(Constants.USER_ACTION, Constants.ACTION_HEART_BEAT1);
        json.put(Constants.HB, Constants.HB_RESULT);
        json.put(Constants.EL_TIME, request_time);
        return json;
    }

    /**
     * 获取连接状态
     *
     * @return
     */
    public int getConnectState() {
        return mConnectState;
    }
}
